.th CR VII 1/4/75
.sh NAME
crfork, crexit, crread, crwrite, crexch, crprior \*- coroutine scheme
.sh SYNOPSIS
.nf
.ft B
int crfork( \fR[\fB stack, nwords \fR]\fB )
int stack[];
int nwords;
.s3
crexit()
.s3
int crread(connector, buffer, nbytes)
int *connector[2];
char *buffer;
int nbytes;
.s3
crwrite(connector, buffer, nbytes)
int *connector[2];
char *buffer;
int nbytes;
.s3
crexch(conn1, conn2, i)
int *conn1[2], *conn2[2];
int i;
.s3
#define logical char *
crprior(p)
logical p;
.fi
.ft R
.sh DESCRIPTION
These functions are named by analogy to
.it "fork, exit, read, write"
(II).
They establish and synchronize `coroutines', which
behave in many respects like a set of processes working
in the same address space.
The functions live in
.it /usr/lib/cr.a.
.s3
Coroutines are placed
on queues to indicate their state of readiness.
One coroutine is always distinguished as `running'.
Coroutines that are runnable but not running
are registered on a `ready queue'.
The head member of the ready queue is started whenever no other
coroutine is specifically caused to be running.
.s3
Each connector heads two
queues: 
.it Connector[0]
is the queue of unsatisfied 
.it crreads
outstanding on the connector.
.it Connector[1]
is the queue of
.it crwrites.
All queues must start empty,
.it i.e.
with heads set to zero.
.s3
.it Crfork
is normally called with no arguments.
It
places the running coroutine at the head of
the ready queue, creates a new coroutine, and starts the new 
one running.
.it Crfork
returns immediately in the new coroutine with value 0,
and upon restarting of the old
coroutine with value 1.
.s3
.it Crexit
stops the running coroutine and does not place it in any queue.
.s3
.it Crread
copies characters from the
.it buffer
of the 
.it crwrite
at the head of the 
.it connector's
write queue to the 
.it buffer
of
.it crread.
If the write queue is empty, copying is delayed and the running
coroutine is placed on the read queue.
The number of characters copied is the minimum of
.it nbytes
and the number of characters remaining in the write
.it buffer,
and is returned as the value of
.it crread.
After copying, the location of the write
.it buffer
and the corresponding
.it nbytes
are updated appropriately.
If zero characters remain, the coroutine of the
.it crwrite
is moved to the head of the ready queue.
If the write queue remains nonempty,
the head member of the read queue is moved to
the head of the ready queue.
.s3
.it Crwrite
queues the running coroutine on the
.it connector's
write queue,
and records the fact that
.it nbytes
(zero or more)
characters in the string
.it buffer
are available to 
.it crreads.
If the read queue is not empty,
its head member is started running.
.s3
.it Crexch
exchanges the read queues of connectors
.it conn1
and
.it conn2
if
\fIi\fR=0; and it exchanges the write queues if
\fIi\fR=1.
If a nonempty read queue that had been paired with an empty write queue
becomes paired with a nonempty write queue,
.it crexch
moves
the head member of that read queue to the head
of the ready queue.
.s3
.it Crprior
sets a priority on the running coroutine to 
control the queuing of
.it crreads
and
.it crwrites.
When queued, the running coroutine will take its place before
coroutines whose priorities exceed
its own priority and after others.
Priorities are compared as logical,
.it i.e.
unsigned,
quantities.
Initially each coroutine's priority is set as large as possible,
so default queuing is
.nh
FIFO.
.hy
.s3
.bd "Storage allocation."
The old and new coroutine share the same activation record
in the function that invoked
.it crfork,
so only one may return from the invoking function,
and then only when the other has completed execution in that function.
.s3
The activation record for each function
execution is dynamically allocated rather than stacked;
a factor of 3 in running time overhead
can result if function calls are very frequent.
The overhead may be overcome by
providing a separate stack for each coroutine and dispensing with
dynamic allocation.
The base (lowest) address and size of the
new coroutine's stack are supplied to
.it crfork
as optional arguments
.it stack
and
.it nwords.
Stacked allocation and dynamic allocation cannot be mixed
in one run.
For stacked operation, obtain the coroutine functions from
.it /usr/lib/scr.a
instead of
.it /usr/lib/cr.a.
.sh FILES
/usr/lib/cr.a
.br
/usr/lib/scr.a
.sh DIAGNOSTICS
`rsave doesn't work' \*- an old C compilation
has called `rsave'.
It must be recompiled to work
with the coroutine scheme.
.sh BUGS
Under /usr/lib/cr.a
each function has just 12 words of anonymous
stack for hard expressions and arguments
of further calls, regardless of actual need.
There is no checking for stack overflow.
.br
Under /usr/lib/scr.a
stack overflow checking is not rigorous.
